use std::collections::VecDeque;
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::sync::{Arc, mpsc};
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::time::Duration;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::error::{EventLoopError, NotSupportedError};
use crate::event_loop::{
    ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopClosed,
};
use crate::platform::pump_events::PumpStatus;
use crate::window::{
    ActivationToken, Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose,
    ResizeDirection, Theme, UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
};
// // pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
pub(crate) use crate::cursor::OnlyCursorImage as PlatformCustomCursor;
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
// pub(crate) use crate::platform_impl::Fullscreen;

// pub(crate) mod common;

pub use window::Window;
mod window;

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct PlatformSpecificEventLoopAttributes {
}

#[derive(Clone, Debug, Default)]
pub struct PlatformSpecificWindowAttributes {
}

#[derive(Debug, Clone)]
pub enum OsError {
    Misc(&'static str),
}

use std::fmt::{self, Display};
impl fmt::Display for OsError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            OsError::Misc(msg) => Display::fmt(msg, formatter),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(u64);

impl From<WindowId> for u64 {
    fn from(window_id: WindowId) -> Self {
        window_id.0
    }
}

impl From<u64> for WindowId {
    fn from(raw_id: u64) -> Self {
        Self(raw_id)
    }
}

impl WindowId {
    pub const fn dummy() -> Self {
        Self(0)
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId {
}

impl DeviceId {
    pub const fn dummy() -> Self {
        Self {}
    }
}

#[derive(Clone, Debug)]
pub struct MonitorHandle {
    name: Option<String>,
}

impl MonitorHandle {
    #[inline]
    pub fn name(&self) -> Option<String> {
        None
    }

    #[inline]
    pub fn native_identifier(&self) -> u32 {
        0
    }

    #[inline]
    pub fn size(&self) -> PhysicalSize<u32> {
        PhysicalSize::new(0, 0)
    }

    #[inline]
    pub fn position(&self) -> PhysicalPosition<i32> {
        PhysicalPosition::new(0, 0)
    }

    #[inline]
    pub fn refresh_rate_millihertz(&self) -> Option<u32> {
        None
    }

    #[inline]
    pub fn scale_factor(&self) -> f64 {
        0.0
    }

    #[inline]
    pub fn video_modes(&self) -> Box<dyn Iterator<Item = VideoModeHandle>> {
        Box::new(std::iter::empty())
    }
}

impl PartialEq for MonitorHandle {
    fn eq(&self, other: &Self) -> bool {
        false
    }
}

impl Eq for MonitorHandle {}

impl PartialOrd for MonitorHandle {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        None
    }
}

impl Ord for MonitorHandle {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        std::cmp::Ordering::Equal
    }
}

impl std::hash::Hash for MonitorHandle {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {

    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VideoModeHandle {
    pub(crate) size: PhysicalSize<u32>,
    pub(crate) bit_depth: u16,
    pub(crate) refresh_rate_millihertz: u32,
    pub(crate) monitor: MonitorHandle,
}

impl VideoModeHandle {
    #[inline]
    pub fn size(&self) -> PhysicalSize<u32> {
        self.size
    }

    #[inline]
    pub fn bit_depth(&self) -> u16 {
        self.bit_depth
    }

    #[inline]
    pub fn refresh_rate_millihertz(&self) -> u32 {
        self.refresh_rate_millihertz
    }

    pub fn monitor(&self) -> MonitorHandle {
        self.monitor.clone()
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct KeyEventExtra {
}

/// The ohos Rosen event loop.
pub struct EventLoop<T: 'static> {
    /// Has `run` or `run_on_demand` been called or a call to `pump_events` that starts the loop
    loop_running: bool,

    window_ids: Vec<WindowId>,

    /// Sender of user events.
    user_events_sender: mpsc::Sender<T>,

    // XXX can't remove RefCell out of here, unless we can plumb generics into the `Window`, which
    // we don't really want, since it'll break public API by a lot.
    /// Pending events from the user.
    pending_user_events: Rc<RefCell<Vec<T>>>,

    /// Event loop window target.
    window_target: RootActiveEventLoop,

    // The file descriptor for the event loop.
    fd: RawFd,
}

impl<T: 'static> EventLoop<T> {
    pub(crate) fn new(
        attributes: &PlatformSpecificEventLoopAttributes,
    ) -> Result<Self, EventLoopError> {
        Err(EventLoopError::NotSupported(NotSupportedError::new()))
    }

    #[inline]
    pub fn create_proxy(&self) -> EventLoopProxy<T> {
        EventLoopProxy::new(self.user_events_sender.clone())
    }

    pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError>
    where
        F: FnMut(crate::event::Event<T>, &RootActiveEventLoop),
    {
        self.run_on_demand(callback)
    }

    pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
    where
        F: FnMut(crate::event::Event<T>, &RootActiveEventLoop),
    {
        Err(EventLoopError::NotSupported(NotSupportedError::new()))
    }

    pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
    where
        F: FnMut(crate::event::Event<T>, &RootActiveEventLoop),
    {
        PumpStatus::Exit(0)
    }

    pub fn window_target(&self) -> &RootActiveEventLoop {
        &self.window_target
    }

    // pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
    // where
    //     F: FnMut(crate::event::Event<T>, &RootActiveEventLoop),
    // {
    // }
}

impl<T> AsFd for EventLoop<T> {
    fn as_fd(&self) -> BorrowedFd<'_> {
        // Return proper file descriptor
        unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
    }
}

impl<T> AsRawFd for EventLoop<T> {
    fn as_raw_fd(&self) -> RawFd {
        // Return the actual raw file descriptor
        self.fd
    }
}

/// A handle that can be sent across the threads and used to wake up the `EventLoop`.
pub struct EventLoopProxy<T: 'static> {
    user_events_sender: mpsc::Sender<T>,
}

impl<T: 'static> Clone for EventLoopProxy<T> {
    fn clone(&self) -> Self {
        EventLoopProxy { user_events_sender: self.user_events_sender.clone() }
    }
}

impl<T: 'static> EventLoopProxy<T> {
    pub fn new(user_events_sender: mpsc::Sender<T>) -> Self {
        Self { user_events_sender }
    }

    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
        Ok(())
    }
}

pub struct ActiveEventLoop {
    /// The application's latest control_flow state
    pub(crate) control_flow: Cell<ControlFlow>,

    /// The application's exit state.
    pub(crate) exit: Cell<Option<i32>>,
}

impl ActiveEventLoop {
    pub fn create_custom_cursor(&self, cursor: CustomCursorSource) -> CustomCursor {
        CustomCursor { inner: PlatformCustomCursor(Arc::new(cursor.inner.0)) }
    }

    #[inline]
    pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
        VecDeque::new()
    }

    #[inline]
    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
        // There's no primary monitor on ohos.
        None
    }

    #[inline]
    pub fn listen_device_events(&self, _allowed: DeviceEvents) {}

    #[inline]
    pub fn system_theme(&self) -> Option<Theme> {
        None
    }

    pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
        self.control_flow.set(control_flow);
    }

    pub(crate) fn control_flow(&self) -> ControlFlow {
        self.control_flow.get()
    }

    pub(crate) fn clear_exit(&self) {
        self.exit.set(None);
    }

    pub(crate) fn exit(&self) {
        self.exit.set(Some(0));
    }

    pub(crate) fn exiting(&self) -> bool {
        self.exit.get().is_some()
    }

    pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
        OwnedDisplayHandle {}
    }

    #[allow(dead_code)]
    fn set_exit_code(&self, code: i32) {
        self.exit.set(Some(code));
    }

    #[allow(dead_code)]
    fn exit_code(&self) -> Option<i32> {
        self.exit.get()
    }
}

#[derive(Clone)]
#[allow(dead_code)]
pub(crate) struct OwnedDisplayHandle {
}

impl OwnedDisplayHandle {

}

